package com.robot.common.utils;
import org.apache.poi.xwpf.usermodel.*;
import org.apache.poi.util.Units;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.nodes.Node;
import org.jsoup.nodes.TextNode;
import org.springframework.mock.web.MockMultipartFile;

import java.io.*;
import java.util.Base64;

public class HtmlToDocxUtils {

    /**
     * 将 HTML 富文本内容转换为 docx 文件
     *
     * @param htmlDoc    富文本 HTML
     * @param tempFileName 文件名称
     * @return
     * @throws Exception 异常
     */
    public static MockMultipartFile convertHtmlToDocx(Document htmlDoc, String tempFileName) throws Exception {
        XWPFDocument document = new XWPFDocument();

        // 处理所有主要的 HTML 元素
        processElement(htmlDoc.body(), document);

//        // 保存到指定路径
//        try (FileOutputStream out = new FileOutputStream(new File(outputPath))) {
//            document.write(out);
//        }
        // 将文档写入字节数组输出流
        try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
            document.write(baos);
            baos.flush();
            byte[] docxBytes = baos.toByteArray();

            // 创建 MultipartFile 对象
            return new MockMultipartFile(
                    tempFileName,              // 文件名称
                    tempFileName,              // 原始文件名称
                    "application/vnd.openxmlformats-officedocument.wordprocessingml.document", // DOCX 类型
                    new ByteArrayInputStream(docxBytes)    // 文件输入流
            );
        }
    }

    /**
     * 处理 HTML 元素
     *
     * @param element   HTML 元素
     * @param document  XWPFDocument 对象
     */
    private static void processElement(Element element, XWPFDocument document) {
        XWPFParagraph paragraph = null;
        for (Node child : element.childNodes()) {
            if (child instanceof Element) {
                Element htmlElement = (Element) child;
                switch (htmlElement.tagName()) {
                    case "h1":
                    case "h2":
                    case "h3":
                    case "h4":
                    case "h5":
                    case "h6":
                        int fontSize = 24 - Integer.parseInt(htmlElement.tagName().substring(1)) * 2;
                        paragraph = document.createParagraph();
                        XWPFRun headingRun = paragraph.createRun();
                        headingRun.setText(htmlElement.text());
                        headingRun.setBold(true);
                        headingRun.setFontSize(fontSize);
                        if (htmlElement.hasAttr("style")) {
                            String style = htmlElement.attr("style");
                            if (style.contains("text-align: center")) {
                                paragraph.setAlignment(ParagraphAlignment.CENTER);
                            } else if (style.contains("text-align: right")) {
                                paragraph.setAlignment(ParagraphAlignment.RIGHT);
                            } else {
                                paragraph.setAlignment(ParagraphAlignment.LEFT);
                            }
                        }
                        break;
                    case "p":
                        paragraph = document.createParagraph();
                        processInlineStyles(htmlElement, paragraph);
                        applyParagraphStyles(element, paragraph);
                        break;
                    case "img":
                        paragraph = document.createParagraph();
                        processImage(htmlElement, paragraph);
                        break;
                    case "ul":
                    case "ol":
                        paragraph = document.createParagraph();
                        processList(htmlElement, paragraph, document);
                        break;
                    default:
                        paragraph = document.createParagraph();
                        processInlineStyles(htmlElement, paragraph);
                        break;
                }
            }
        }
    }

    /**
     * 处理图片
     *
     * @param imgElement HTML 图片元素
     * @param paragraph  XWPFParagraph 对象
     */
    private static void processImage(Element imgElement, XWPFParagraph paragraph) {
        String imgBase64 = imgElement.attr("src");

        // 检查 src 是否包含 Base64 数据
        if (imgBase64.startsWith("data:image")) {
            String base64Data = imgBase64.substring(imgBase64.indexOf(",") + 1);

            // 解码 Base64 数据
            byte[] imageBytes = Base64.getDecoder().decode(base64Data);

            try (InputStream is = new ByteArrayInputStream(imageBytes)) {
                XWPFRun run = paragraph.createRun();
                run.addPicture(is, XWPFDocument.PICTURE_TYPE_PNG, "image.png", Units.toEMU(200), Units.toEMU(200));
            } catch (Exception e) {
                System.out.println("图片加载失败: " + e.getMessage());
            }
        }
    }

    /**
     * 处理内联样式
     *
     * @param element   HTML 元素
     * @param paragraph XWPFParagraph 对象
     */
    private static void processInlineStyles(Element element, XWPFParagraph paragraph) {
        // 检查段落是否有样式（例如 text-indent）
        if (element.hasAttr("style")) {
            String style = element.attr("style");
            // 处理首行缩进
            if (style.contains("text-indent")) {
                int indentValue = extractIndentValue(style);
                paragraph.setIndentationFirstLine(indentValue);
            }
        }
        for (Node child : element.childNodes()) {
            XWPFRun run = paragraph.createRun();
            if (child instanceof TextNode) {
                run.setText(((TextNode) child).text());
            } else if (child instanceof Element) {
                Element childElement = (Element) child;
                applyStylesToRun(childElement, run); // 递归处理嵌套样式
            }
        }
    }

    /**
     * 处理列表
     *
     * @param listElement HTML 列表元素
     * @param paragraph   XWPFParagraph 对象
     * @param document    XWPFDocument 对象
     */
    private static void processList(Element listElement, XWPFParagraph paragraph, XWPFDocument document) {
        for (Element listItem : listElement.children()) {
            if (listItem.tagName().equals("li")) {
                paragraph.setStyle("List Bullet");
                XWPFRun run = paragraph.createRun();
                run.setText(listItem.text());
            }
        }
    }
    private static int extractIndentValue(String style) {
        String[] styles = style.split(";");
        for (String s : styles) {
            if (s.trim().startsWith("text-indent")) {
                String indentStr = s.split(":")[1].trim();
                try {
                    if (indentStr.endsWith("px")) {
                        // 如果是 px 单位
                        indentStr = indentStr.replace("px", "").trim();
                        // 1 px 大约等于 0.75 点，换算为 Word 中的单位 (20分之一点)
                        return (int) (Double.parseDouble(indentStr) * 15);
                    } else if (indentStr.endsWith("em")) {
                        // 如果是 em 单位
                        indentStr = indentStr.replace("em", "").trim();
                        // 假设 1 em 约等于 12 point，进行换算
                        return (int) (Double.parseDouble(indentStr) * 12 * 20);
                    } else {
                        // 如果没有单位默认为 px 单位处理
                        return (int) (Double.parseDouble(indentStr) * 15);
                    }
                } catch (NumberFormatException e) {
                    System.err.println("无法解析 text-indent 值: " + indentStr);
                }
            }
        }
        return 0; // 如果没有找到 text-indent 返回 0
    }

    private static void applyParagraphStyles(Element element, XWPFParagraph paragraph) {

        if (element.hasAttr("style")) {
            String style = element.attr("style");
            // 处理对齐方式
            if (style.contains("text-align: center")) {
                paragraph.setAlignment(ParagraphAlignment.CENTER);
            } else if (style.contains("text-align: right")) {
                paragraph.setAlignment(ParagraphAlignment.RIGHT);
            } else if (style.contains("text-align: justify")) {
                paragraph.setAlignment(ParagraphAlignment.BOTH);
            } else {
                paragraph.setAlignment(ParagraphAlignment.LEFT);
            }

            // 处理首行缩进
            if (style.contains("text-indent")) {
                int indentValue = extractIndentValue(style);
                paragraph.setIndentationFirstLine(indentValue);  // 设置首行缩进值
            }
        }
    }
    private static void applyStylesToRun(Element element, XWPFRun run) {
        // 处理字体颜色
        if (element.hasAttr("style")) {
            String style = element.attr("style");
            if (style.contains("color")) {
                String color = style.split("color:")[1].split(";")[0].trim();
                // 处理颜色值
                if (color.startsWith("#")) {
                    run.setColor(color.substring(1)); // 去掉 '#'
                } else if (color.startsWith("rgb")) {
                    // 处理 rgb 颜色
                    String[] rgb = color.replace("rgb(", "").replace(")", "").split(",");
                    String hexColor = String.format("#%02x%02x%02x",
                            Integer.parseInt(rgb[0].trim()),
                            Integer.parseInt(rgb[1].trim()),
                            Integer.parseInt(rgb[2].trim()));
                    run.setColor(hexColor.substring(1)); // 去掉 '#'
                }
            }
        }
        if (element.hasAttr("style")) {
            String style = element.attr("style");
            if (style.contains("font-size")) {
                String fontSize = style.split("font-size:")[1].split(";")[0].trim();
                if (fontSize.endsWith("pt")) {
                    run.setFontSize(Integer.parseInt(fontSize.replace("pt", "").trim()));
                }
            }
            // 处理字体
            String fontFamily = getFontFamily(style);
            if (fontFamily != null) {
                run.setFontFamily(fontFamily);
            }
        }

        // 处理子元素内联样式，如 strong、em、u、a 等
        switch (element.tagName()) {
            case "strong": // 加粗
                run.setBold(true);
                break;
            case "em": // 斜体
                run.setItalic(true);
                break;
            case "u": // 下划线
                run.setUnderline(UnderlinePatterns.SINGLE);
                break;
            case "a": // 超链接
                run.setColor("0000FF"); // 设置超链接颜色为蓝色
                run.setUnderline(UnderlinePatterns.SINGLE); // 下划线
                break;
        }

        // 递归处理子节点，确保每个节点的文本都能正确设置
        for (Node child : element.childNodes()) {
            if (child instanceof TextNode) {
                // 如果是文本节点，直接设置文本
                run.setText(((TextNode) child).text());
            } else if (child instanceof Element) {
                // 如果是嵌套的 HTML 元素，递归处理它的样式和文本
                applyStylesToRun((Element) child, run);
            }
        }
    }
    private static String getFontFamily(String style) {
        if (style.contains("font-family")) {
            String fontFamily = style.split("font-family:")[1].split(";")[0].trim();
            return fontFamily;
        }
        return null;
    }
}
